// 判断参数是否是其中之一
export function oneOf (value, validList) {
  for (let i = 0; i < validList.length; i++) {
    if (value === validList[i]) {
      return true
    }
  }
  return false
}

/**
 * 延迟执行
 * @param ms
 * @returns {Promise<any>}
 */
 export function timeout (ms) {
  return new Promise(resolve => {
    setTimeout(resolve, ms)
  })
}

/**
 * 防抖函数
 * @param {Function} event 执行事件
 * @param {Number} time 延迟时间
 */
 export function debounce (event, time) {
  return function (...args) {
    clearTimeout(timer)
    timer = setTimeout(() => {
      event.apply(this, args)
    }, time)
  }
}

/**
 * 节流函数
 * @param {Function} event 执行事件
 * @param {Number} time 延迟时间
 */
export function throttle (event, time) {
  return function (...args) {
    if (Date.now() - pre > time) {
      clearTimeout(timer)
      timer = null
      pre = Date.now()
      event.apply(this, args)
    } else if (!timer) {
      timer = setTimeout(() => {
        // event.apply(this, args)
      }, time)
    }
  }
}

export function trim (str) {
  if (String.prototype.trim) {
    return str === null ? '' : String.prototype.trim.call(str)
  } else {
    return str.replace(/(^\s*)|(\s*$)/g, '')
  }
}

export function isArray (arr) {
  if (!Array.isArray) {
    Array.isArray = (arg) => {
      return Object.prototype.toString.call(arg) === '[object Array]'
    }
  }
  return Array.isArray(arr)
}

export function isEmpty (str) {
  // eslint-disable-next-line
  if (typeof str === 'undefined' || str === null || !(str === str) || str.toString().includes('NaN')) str = ''
  const reg = new RegExp(/^[\s]*$/)
  str = trim(str)
  return reg.test(str)
}

export function typeOf(obj) {
  const toString = Object.prototype.toString;
  const map = {
      '[object Boolean]'  : 'boolean',
      '[object Number]'   : 'number',
      '[object String]'   : 'string',
      '[object Function]' : 'function',
      '[object Array]'    : 'array',
      '[object Date]'     : 'date',
      '[object RegExp]'   : 'regExp',
      '[object Undefined]': 'undefined',
      '[object Null]'     : 'null',
      '[object Object]'   : 'object'
  };
  return map[toString.call(obj)];
}

export function deepCopy (data) {
  const t = typeOf(data)
  let o

  if (t === 'array') {
    o = []
  } else if (t === 'object') {
    o = {}
  } else {
    return data
  }

  if (t === 'array') {
    for (let i = 0; i < data.length; i++) {
      o.push(deepCopy(data[i]))
    }
  } else if (t === 'object') {
    for (let i in data) {
      o[i] = deepCopy(data[i])
    }
  }
  return o
}

/**
 * 枚举转换表格数据
 * @param {*} arr  枚举列表
 * @param {*} fmtLabel
 * @param {*} fmtValue
 * @returns
 */
export function dataProvider (arr, fmtLabel = 'label', fmtValue = 'value') {
  let obj = {}
  if (typeOf(arr) !== 'array') {
    console.log('dataProvider must input array')
    return
  }
  arr.forEach(r => {
    obj[r[fmtValue]] = r[fmtLabel]
  })
  return obj
}

export function scrollTop (el, from = 0, to, duration = 500, endCallback) {
  if (!window.requestAnimationFrame) {
    window.requestAnimationFrame =
      window.webkitRequestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      window.msRequestAnimationFrame ||
      function (callback) {
        return window.setTimeout(callback, 1000 / 60)
      }
  }
  const difference = Math.abs(from - to)
  const step = Math.ceil((difference / duration) * 50)

  function scroll (start, end, step) {
    if (start === end) {
      endCallback && endCallback()
      return
    }

    let d = start + step > end ? end : start + step
    if (start > end) {
      d = start - step < end ? end : start - step
    }

    if (el === window) {
      window.scrollTo(d, d)
    } else {
      el.scrollTop = d
    }
    window.requestAnimationFrame(() => scroll(d, end, step))
  }
  scroll(from, to, step)
}

export function add (a, b) {
  let c
  let d
  let e
  try {
    c = a.toString().split('.')[1].length
  } catch (f) {
    c = 0
  }
  try {
    d = b.toString().split('.')[1].length
  } catch (f) {
    d = 0
  }
  // eslint-disable-next-line
  return (e = Math.pow(10, Math.max(c, d)), (mul(a, e) + mul(b, e)) / e)
}

export function sub (a, b) {
  let c
  let d
  let e
  try {
    c = a.toString().split('.')[1].length
  } catch (f) {
    c = 0
  }
  try {
    d = b.toString().split('.')[1].length
  } catch (f) {
    d = 0
  }
  // eslint-disable-next-line
  return (e = Math.pow(10, Math.max(c, d)), (mul(a, e) - mul(b, e)) / e)
}

export function mul (a, b) {
  let c = 0
  const d = a.toString()
  const e = b.toString()
  try {
    c += d.split('.')[1].length
  } catch (f) {}
  try {
    c += e.split('.')[1].length
  } catch (f) {}
  // eslint-disable-next-line
  return Number(d.replace('.', '')) * Number(e.replace('.', '')) / Math.pow(10, c)
}

export function div (a, b) {
  let c
  let d
  let e = 0
  let f = 0
  try {
    e = a.toString().split('.')[1].length
  } catch (g) {}
  try {
    f = b.toString().split('.')[1].length
  } catch (g) {}
  // eslint-disable-next-line
  return (c = Number(a.toString().replace('.', '')), d = Number(b.toString().replace('.', '')), mul(c / d, Math.pow(10, f - e)))
}

function camelCase (name) {
  const SPECIAL_CHARS_REGEXP = /([\\:\-\\_]+(.))/g
  const MOZ_HACK_REGEXP = /^moz([A-Z])/
  return name.replace(SPECIAL_CHARS_REGEXP, function (_, separator, letter, offset) {
    return offset ? letter.toUpperCase() : letter
  }).replace(MOZ_HACK_REGEXP, 'Moz$1')
}

export function getStyle (element, styleName) {
  if (!element || !styleName) return null
  styleName = camelCase(styleName)
  if (styleName === 'float') {
    styleName = 'cssFloat'
  }
  try {
    const computed = document.defaultView.getComputedStyle(element, '')
    return element.style[styleName] || computed ? computed[styleName] : null
  } catch (e) {
    return element.style[styleName]
  }
}

export function firstUpperCase (str) {
  return str.toString()[0].toUpperCase() + str.toString().slice(1)
}

// Find components upward
export function findComponentUpward (context, componentName, componentNames) {
  if (typeof componentName === 'string') {
    componentNames = [componentName]
  } else {
    componentNames = componentName
  }

  let parent = context.$parent
  let name = parent.$options.name
  while (parent && (!name || componentNames.indexOf(name) < 0)) {
    parent = parent.$parent
    if (parent) name = parent.$options.name
  }
  return parent
}

// Find component downward
export function findComponentDownward (context, componentName) {
  const childrens = context.$children
  let children = null

  if (childrens.length) {
    for (const child of childrens) {
      const name = child.$options.name
      if (name === componentName) {
        children = child
        break
      } else {
        children = findComponentDownward(child, componentName)
        if (children) break
      }
    }
  }
  return children
}

// Find components downward
export function findComponentsDownward (context, componentName) {
  return context.$children.reduce((components, child) => {
    if (child.$options.name === componentName) components.push(child)
    const foundChilds = findComponentsDownward(child, componentName)
    return components.concat(foundChilds)
  }, [])
}

// Find components upward
export function findComponentsUpward (context, componentName) {
  const parents = []
  const parent = context.$parent
  if (parent) {
    if (parent.$options.name === componentName) parents.push(parent)
    return parents.concat(findComponentsUpward(parent, componentName))
  } else {
    return []
  }
}

// Find brothers components
export function findBrothersComponents (context, componentName, exceptMe = true) {
  const res = context.$parent.$children.filter(item => {
    return item.$options.name === componentName
  })
  const index = res.findIndex(item => item._uid === context._uid)
  if (exceptMe) res.splice(index, 1)
  return res
}

// replace conditions
export function replaceConditions (data) {
  if (!isArray(data)) return
  return data.map(ret => {
    if (ret.filters && ret.filters.length) ret.filters = replaceConditions(ret.filters)
    if (ret.conditions) ret.conditions = JSON.parse(JSON.stringify(ret.conditions)).pop()
    return ret
  })
}
